package gorm

import (
	"fmt"
	"github.com/bighuangbee/gokit/tools"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"strings"
	"time"
	"gorm.io/driver/mysql"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm/logger"
)

type Options struct {
	Address string
	UserName string
	Password string
	DBName string
	Driver string
	Logger  *logrus.Logger
	//Tracer  trace.TracerProvider
	Charset string
}

func New(opt *Options) (*gorm.DB, error) {
	if opt.Charset == ""{
		opt.Charset = "utf8mb4"
	}

	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=True&loc=Local",
		opt.UserName, opt.Password, opt.Address, opt.DBName, opt.Charset)

	mysqlConfig := mysql.Config{
		DSN:                       dsn,   // DSN data source name
		//DefaultStringSize:         191,   // string 类型字段的默认长度
		DisableDatetimePrecision:  true,  // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据版本自动配置
	}
	if db, err := gorm.Open(mysql.New(mysqlConfig)); err != nil {
		return nil, err
	} else {
		db.Logger = logger.New(
			LogWriter{opt.Logger},
			logger.Config{
				SlowThreshold:              time.Second,   // Slow SQL threshold
				LogLevel:                   logger.Info,   // Log level
				IgnoreRecordNotFoundError: true,           // Ignore ErrRecordNotFound error for logger
				Colorful:                  false,          // Disable color
			},
		)
		db.NamingStrategy = schema.NamingStrategy{
			TablePrefix: "",
			SingularTable: true,
		}

		instance, err := db.DB()
		if err != nil{
			return nil, err
		}
		instance.SetMaxIdleConns(5)
		instance.SetMaxOpenConns(50)
		return db, nil
	}
}

type LogWriter struct{
	Logger  *logrus.Logger
}

func (l LogWriter) Printf(format string, v ...interface{}) {
	path := strings.Split(v[0].(string), "/")
	pathLen := len(path)
	if pathLen > 3{
		v[0] = path[pathLen-3]+"/"+path[pathLen-2]+"/"+path[pathLen-1]
	}

	msg := []interface{}{}
	msg = append(msg, tools.Green(tools.ToStr(v[0])))
	if len(v) == 4{
		t, ok := v[1].(float64)
		if !ok{
			t = 0
		}
		msg = append(msg, tools.Yellow(tools.ToStr(fmt.Sprintf("%.3fms", t))))
		msg = append(msg, tools.Cyan(fmt.Sprintf("rows:%s", tools.ToStr(v[2]))))
		msg = append(msg, v[3])
	}else if len(v) == 5{
		t, ok := v[2].(float64)
		if !ok{
			t = 0
		}
		msg = append(msg, tools.Red(tools.ToStr(v[1])))
		msg = append(msg, tools.Yellow(tools.ToStr(fmt.Sprintf("%.3fms", t))))
		msg = append(msg, tools.Cyan(fmt.Sprintf("rows:%s", tools.ToStr(v[3]))))
		msg = append(msg, v[4])
	}

	if l.Logger != nil{
		l.Logger.Info(msg)
	}else{
		fmt.Println(msg)
	}
}
